<?php
/**
 * 模型抽象类
 *
 * 一个关于各种模型的基本行为类，每个模型都必须继承这个类的方法
 * 
 * 
 * 
 */

abstract class Model
{
    var $ins_data;
    var $db = null;
    var $table;
    var $in_var;
    var $tpl;
    var $upload;
    var $sys_conf_var;
    var $query;
    var $order;
    var $limit;
    var $db_insert_id;
    var $page;
    var $where = array();
    var $join = array();
    var $from = array();
    var $groupby  = array();
    var $having = array();
    var $table_suffix = '';
    var $last_id;

    /**
     * 构造函数
     * @global $this->db 数据库类
     * @global $table 数据库表列表
     *
     * @return Null
     */
    function __construct()
    {
        global $tpl,$sys_conf_var,$in_var,$upload,$logger,$admin_lang;

        $this->table 		= $sys_conf_var['table'];
        $this->in_var 		= $in_var;
        $this->tpl 			= $tpl;
        $this->lang 		= $admin_lang;
        $this->upload 		= $upload;
        $this->sys_conf_var = $sys_conf_var;
        $this->last_id		= &$this->db_insert_id;
    }

    /**
     * 链接数据库
     */
    function connectionDB()
    {
        global $db;

        if(!$this->db) $this->db = $db = DBFactory::getDBConnection($this->sys_conf_var['db']);   //get a batabase instance
    }


    /**
     * 加载类库文件
     *
     * @param string $class
     */
    function loadClass($class)
    {
        $numargs = func_num_args();

        if($numargs == 1)
        {
            $this->$class = new $class();
        }
        else
        {
            $arg_list = func_get_args();

            for ($i = 0; $i < $numargs; ++$i) {
                if($i > 0)
                {
                    $args[] = '$arg_list[' . $i . ']';
                }
            }

            eval('$this->$class = new $class(' . implode(',',$args) . ');');
        }

        return $this->$class;
    }

    /**
     * 加载模型
     *
     * @param string $class
     */
    function loadModel($class)
    {
        $numargs = func_num_args();

        if($numargs == 1)
        {
            $this->$class = new $class();
        }
        else
        {
            $arg_list = func_get_args();

            for ($i = 0; $i < $numargs; $i++) {
                if($i > 0)
                {
                    $args[] = '$arg_list[' . $i . ']';
                }
            }

            eval('$this->$class = new $class(' . implode(',',$args) . ');');
        }

        return $this->$class;
    }

    /**
     * 添加处理数据
     *
     * @param string $var   变量名
     * @param steing $value 值
     * @param int    $modified  = 1 : 为添加修饰符
     */
    function addData($var,$value = null,$modified = 1)
    {
        if (is_array($var) || $var instanceof ArrayObject)
        {
            foreach ($var as $key => $val)
            {
                if ($key != '')
                {
                    $this->ins_data[$key] = $val;
                    $this->modified[$key] = $modified;
                }
            }
        }
        else
        {
                $this->ins_data[$var] = $value;
                $this->modified[$var] = $modified;
        }
    }

    /**
     * 修改数组里的值
     *
     * @param string $key
     * @param string $val
     */
    function chgData($key,$val)
    {
        $this->ins_data[$key] = $val;
    }

    /**
     * 删除一个数据
     *
     * @param string $key
     */
    function delData($key)
    {
        unset($this->ins_data[$key]);
    }

    /**
     * 清空数据
     *
     */
    function cleanData()
    {
        unset($this->ins_data);
    }

    /**
     * 清空条件
     *
     */
    function cleanConditions()
    {
        unset($this->where);
        unset($this->conditions);
        unset($this->from);
        unset($this->join);
        unset($this->join_table);
        unset($this->groupby);
        unset($this->groupby_where);
        unset($this->having);
        unset($this->having_where);
        unset($this->order);
        unset($this->limit);
    }

    /**
     * 处理插入数据库字符串
     *
     * @param string $string
     * @return string
     */
    function ensql($string)
    {
        return mysql_real_escape_string($string);
    }

    /**
     * 插入数据库数据
     *
     * @param string $table
     * @param boolean $delayed
     * @return boolean
     */
    function dataInsert($table, $delayed=false)
    {
        try
        {
            //构建SQL语句
            $ins_data_num = count($this->ins_data);
            $foreach_i = 0;
            $query = 'Insert ' . ($delayed===true ? 'delayed ' : '') . 'into ' . $this->getTable($table) . " \n(\n";
            $query_key = '';
            $query_val = '';

            foreach($this->ins_data as $key=>$val)
            {
                if(strlen($val)>0)
                {
                    if($foreach_i == 0)
                    {
                        $query_key .= $key;

                        if($this->modified[$key])
                        {
                            $query_val .= "'" . $this->ensql($val) . "'";
                        }
                        else
                        {
                            $query_val .= $this->ensql($val);
                        }
                    }
                    else
                    {
                        $query_key .= ",\n{$key}";

                        if($this->modified[$key])
                        {
                            $query_val .= ",\n'" . $this->ensql($val) . "'";
                        }
                        else
                        {
                            $query_val .= ",\n" . $this->ensql($val);
                        }
                    }

                    $foreach_i = $foreach_i + 1;
                }
            }

            $query .= $query_key . "\n) \nValues \n(\n" . $query_val . "\n)";

            $this->cleanData();

            //SQL语句执行
            if(!$this->db) throw new AppException('Not fond object : $this->db .');
            //echo $query;
            if($result = $this->db->Execute($query))
            {
                $this->db_insert_id = $this->db->getInsertID();
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 添加条件语句
     *
     * @param string $field  表字段
     * @param string $value	 值
     * @param string $terms  条件
     * @param string $type  条件逻辑运算符
     * @param string $modify  条件修饰符
     */
    function where($field,$value,$terms = "=",$type = "and",$modify = 1)
    {
        $prefix = (count($this->where) == 0) ? '' : $type . ' ';

        if(strtolower($terms) == 'in' || strtolower($terms) == 'not in')
        {
            $this->where[] = $prefix . $field . ' ' . $terms . ' (' . $value . ')';
        }
        elseif(strtolower($terms) == 'like')
        {
            $this->where[] = $prefix . $field . ' ' . $terms . ' "%' . $value . '%"';
        }
        else
        {
            if ($value !== NULL)
            {
                if($modify)
                {
                    $value = "'" . $this->ensql($value) . "'";
                }

                $this->where[] = $prefix . $field . ' ' . $terms . ' ' . $value;
            }
            else
            {
                $this->where[] = $prefix . $field;
            }
        }

        $this->conditions = implode(" ",$this->where);
    }

    /**
     * 解析表解析符
     *
     * @param string $table
     * @return string
     */
    function table_aliases($table)
    {
        $temp = explode(' ',$table);

        if(count($temp) > 1)
        {
            return $this->getTable($temp[0]) . ' ' . end($temp);
        }
        else
        {
             return $this->getTable($temp[0]);
        }
    }

    /**
     * 得到表名
     *
     */
    function getTable($table)
    {
        if(!$this->table[$table]) die('this table does not exist - ' . $table);

        return $this->table[$table] . $this->table_suffix;
    }

    /**
     * 设置多表查询
     *
     * @param string $table
     */
    function from($table)
    {
        if (!$table = $this->table_aliases($table)) return false;

        $this->from[] = $table;

        $this->from_table = implode(",",$this->from);
    }




    /**
     * join查询
     *
     * @param string $table
     * @param string $cond
     * @param string $type
     */
    function join($table, $cond, $type = '')
    {
        if (!$table = $this->table_aliases($table)) return false;

        if ($type != '')
        {
            $type = strtoupper(trim($type));

            if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
            {
                $type = '';
            }
            else
            {
                $type .= ' ';
            }
        }

        // Strip apart the condition and protect the identifiers
        if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
        {
            $cond = $match[1] . $match[2] . $match[3];
        }

        $this->join[] = $type . 'JOIN ' . $table . ' ON ' . $cond;

        $this->join_table = " " . implode(" ",$this->join);
    }

    /**
     * 添加groupBy 条件
     *
     * @param string $field
     */
    function groupby($field)
    {
        $this->groupby[] = $field;

        $this->groupby_where = " GROUP BY " . implode(",",$this->groupby) . ' ';
    }


    /**
     * 添加having 条件
     *
     * @param string $field
     */
    function having($field,$value,$terms = '=', $type = 'and')
    {
        $prefix = (count($this->having) == 0) ? '' : $type . ' ';

        if (is_null($value))
        {
            $value = ' IS NULL';
        }

        if(!is_integer($value))
        {
            $value = "'" . $value . "'";
        }


        if(strtolower($terms) == 'in' || strtolower($terms) == 'not in')
        {
            $this->having[] = $prefix . $field . ' ' . $terms . ' (' . $value . ')';
        }
        else
        {
            $this->having[] = $prefix . $field . ' ' . $terms . ' ' . $value;
        }

        $this->having_where = " HAVING " . implode(" ",$this->having) . ' ';
    }

    /**
     * 设置记录上限
     *
     * @param int $limit
     */
    function setLimit($limit)
    {
        if ($limit) $this->limit = $limit;
    }

    /**
     * 设置排序
     *
     * @param string $order
     */
    function setOrder($order = ' order by ID desc')
    {
        $this->order = " " . $order . " ";
    }

    /**
     * 设置取得的页数
     *
     * @param int $page
     */
    function setPage($page)
    {
        $this->page = $page;
    }

    /**
     * 更新数据库数据
     *
     * @param string $table 表名
     * @param string $where 查询条件
     * @return boolean
     */
    function dataUpdate($table)
    {
        try
        {
            //构建SQL语句
             $foreach_i = 0;
             $query     = "update " . $this->getTable($table) . " set ";
             $query_key = "";
             $query_val = "";
             $where = $this->conditions ? ' where ' . $this->conditions : '';

             foreach($this->ins_data as $key=>$val)
            {
                      if($foreach_i == 0)
                    {
                         $query_key = "{$key}";

                         if($this->modified[$key])
                        {
                            $query_val = "='" . $this->ensql($val) . "'";
                        }
                        else
                        {
                            $query_val = "=" .$this->ensql($val);
                        }

                        $query .= $query_key . $query_val;
                    }
                    else
                    {
                         $query_key = ",{$key}";

                         if($this->modified[$key])
                        {
                            $query_val = "='" .  $this->ensql($val) . "'";
                        }
                        else
                        {
                            $query_val = "=" . $this->ensql($val);
                        }

                        $query .= $query_key . $query_val;
                       }

                     $foreach_i = $foreach_i + 1;
             }

            $query .= " $where";

            $this->cleanConditions();
            $this->cleanData();

            if(!$this->db) throw new AppException('Not fond object : $this->db .');
            //SQL语句执行
             if($this->db->query($query))
            {
                 return true;
            }
             else
             {
                 return false;
            }
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 删除数据
     *
     * @param string $table
     * @param string $which
     * @param string $id
     * @param string $method
     * @return boolean
     */
    function dataDel($table)
    {
        $where = $this->conditions ? ' where ' . $this->conditions : '';

        try
        {
            /**Modified by jefurry*/
            if(isset($this->order))
            {
                $order = ' ' . $this->order;
            }

            if(isset($this->page) && isset($this->limit))
            {
                $offset = ($this->page - 1) * $this->limit;
                $limit = ' limit ' . $this->limit;

                $this->page_limit = $limit;
            }
            //构建SQL语句
             $query = "Delete From " . $this->getTable($table) . $where;

             $this->cleanConditions();

             if(!$this->db) throw new AppException('Not fond object : $this->db .');

             if($this->db->Execute($query))
            {
                 return true;
            }
             else
             {
                 return false;
            }
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 取得记录数量
     *
     * @param string $table  传入的数据表
     * @param string $where  查询条件
     * @return int   传回记录条数
     */
    function dataNum($table)
    {
        $this->from($table);

        $where = $this->conditions ? ' where ' . $this->conditions : '';

        $this->cleanConditions();

        try
        {
            if(!$this->db) throw new AppException('Not fond object : $this->db .');

            $sql = "select count(*) as Num from " . $this->from_table . $where;

            $result = $this->db->getRow($sql);

            return $result['Num'];
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 得到一组数据
     *
     * @param string $table  数据表名
     * @param string $where  查询条件
     * @param string $select  查询字段
     * @param string $sql  自定义sql语句,当$sql存在是,前面参数无效
     * @return array      得到一条记录
     */
    function getDataInfo($table,$select = '*', $preserved_keys=NULL)
    {
        $this->from($table);

        $where = $this->conditions ? ' where ' . $this->conditions : '';

        try
        {
            $sql = $sql ? $sql : "select " . $select ." from "
            . $this->from_table
            . $this->join_table
            . $where
            . $this->groupby_where
            . $this->having_where
            . $this->order;

            $this->cleanConditions();

            if(!$this->db) throw new AppException('Not fond object : $this->db .');

            $result = $this->db->getRow($sql);

            return $this->unformatDate($result, $preserved_keys);
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 反译数据库记录
     * @param $result
     * @return unknown_type
     */
    function unformatDate($result, $preserved_keys=NULL)
    {
        if( !empty( $result ) )
        {
            foreach($result as $key=>&$value )
            {
                if (!$preserved_keys || !in_array($key, $preserved_keys))
                {
                    $result[$key] = stripslashes( $value );
                }
            }
        }

        return $result;
    }

    /**
     * 得到数据列表
     *
     * @param string $table  数据表名
     * @param string $select  查询字段
     * @return array   返回数据记录列表
     */
    function getDataList($table,$select = '*')
    {
        $this->from($table);

        $where = $this->conditions ? ' where ' . $this->conditions : '';

        if(isset($this->order))
        {
            $order = ' ' . $this->order;
        }

        if(isset($this->page) && isset($this->limit))
        {
            $offset = ($this->page - 1) * $this->limit;
            $limit = ' limit ' . $this->limit . ' offset ' . $offset;

            $this->page_limit = $this->limit;
        }

        try
        {
            $this->query = "select " . $select . " from " . $this->from_table
            . $this->join_table
            . $where
            . $this->groupby_where
            . $this->having_where
            . $order
            . $limit;

            $this->cleanConditions();

            if(!$this->db) throw new AppException('Not fond object : $this->db .');

            $result = $this->db->Execute($this->query);

            while(!$result->EOF)
            {
                $list[] = $this->unformatDate($result->fields);
                $result->moveNext();
            }

            return $list;
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }

    /**
     * 自定义查询
     *
     * @param string $sql 查询语句
     * @param int $type 返回类型 1=多条记录，2=单条记录
     * @return array
     */
    function customQuery($sql,$type = 1)
    {
        $this->query = $sql;
        try
        {
            if($type == 1)
            {
                if(!$this->db) throw new AppException('Not fond object : $this->db .');

                $result = $this->db->Execute($this->query);

                while(!$result->EOF)
                {
                    $list[] = $result->fields;
                    $result->moveNext();
                }

                return $list;
            }
            else
            {
                $result = $this->db->getRow($this->query);

                return $result;
            }
        }
        catch (MySqlException $e)
        {
            $e->showError();
        }
    }


    /**
     * 得到上一个多记录查询语句的总记录数和总页数
     *
     * @param string $url  分页链接地址
     */
    function getPageInfo($url,$showPages = 7)
    {
        if ($this->query)
        {
            $pattern 			= '/select (.*?) from (.*)limit(.*)/i';
            $replacement 		= 'from $2';
            $count_query 		= preg_replace($pattern, $replacement, $this->query);

            // 处理有 group by 的情况
            $pattern_group      = '/\s+group\s+by\s+(\([a-z\s,]+\)|[a-z]+)\s+/i';
            $matches            = array();
            if (preg_match($pattern_group, $count_query, $matches))
            {
                $group_by    = trim($matches[1], '()');
                $count_query = preg_replace($pattern_group, ' ', $count_query);
                $count_key   = 'distinct ' . $group_by;
            }
            else
            {
                $count_key = '*';
            }

            $count_query = "select count({$count_key}) as num " . $count_query;

            try
            {
                if(!$this->db) throw new AppException('Not fond object : $this->db .');

                $result = $this->db->getRow($count_query);
            }
            catch (MySqlException $e)
            {
                $e->showError();
            }

            $page = $this->_getPageInfo($url, $result['num'], $this->page_limit, $this->page,ceil($result['num']/$this->page_limit));

            unset($this->page_limit);
            unset($this->page);

            return $page;
        }
        else
        {
            return -1;
        }
    }

    /**
     * 根据结果集获取分页信息
     * @author Jefurry <jefurry@taomee.com>
     * @param $url
     * @param $num 记录总数
     * @param $page
     * @param $page_size
     * @showPages
     * @return Array
     */
    public function getPageInfoByResult($url, $num, $page, $page_size, $showPages=5)
    {
        $page = $this->_getPageInfo($url, $num, $page_size, $page, $showPages);

        return $page;
    }


    /**
     * 生成页面列表
     * @param $url
     * @param $total
     * @param $page_size
     * @param $page
     * @param $showPages
     * @return unknown_type
     */
    function _getPageInfo($url,$total,$page_size,$page,$showPages=5)
    {
        $page_info['result_num']   = $total;

        $page_info['page_num']     = ceil($total/$page_size);
        $page_info['current_page'] = $page;
        $page_info['page']         = page($page_info['page_num'],$page,$url,$showPages);

        // 范围：当前是从第X项到第Y项
        $offset = ($page-1)*$page_size;
        $upper  = min($offset + $page_size - 1, $total-1);
        $page_info['range']        = array($offset+1, $upper+1);

        return $page_info;
    }

    /**
     * 选择用户数据库，当查询用户分库时使用
     *
     * @param int $uid 用户id
     */
    function selectUserDB($uid)
    {
        $uid = intval($uid);
        if (!$uid)
        {
            throw new AppException('input uid is NULL when on selecting DB');
        }

        $this->connectionDB();

        $this->db->selectDB($this->sys_conf_var['db']['db_name'] . '_user_' . $this->get_db_num($uid));

        $this->table_suffix = '_' . $this->get_tb_num($uid);
    }

    /**
     * 选择主库
     */
    function selectMainDB()
    {
        $this->connectionDB();

        $this->db->selectDB($this->sys_conf_var['db']['db_name']);

        $this->table_suffix = '';
    }

    /**
     * 选择班级库
     */
    function selectClassDB()
    {
        $this->connectionDB();

        $this->db->selectDB($this->sys_conf_var['db']['db_name'] . '_class');

        $this->table_suffix = '';
    }

    /**
     * 选择组件库
     *
     * @param int $uid 用户id
     */
    function selectAppDB($uid)
    {
        $uid = intval($uid);
        if (!$uid)
        {
            throw new AppException('input uid is NULL when on selecting DB');
        }

        $this->connectionDB();

        $this->db->selectDB($this->sys_conf_var['db']['db_name'] . '_app_' . $this->get_db_num($uid));

        $this->table_suffix = '_' . $this->get_tb_num($uid);
    }


    /**
     * 路由数据库
     *
     * @param int $uid
     * @return int
     */
    function get_db_num($uid)
    {
        $num = @floor(($uid%10000)/100);

        return str_pad($num, 2, '0', STR_PAD_LEFT);
    }

    /**
     * 路由数据表
     *
     * @param unknown_type $uid
     * @return unknown
     */
    function get_tb_num($uid)
    {
        $num = @floor(($uid%10000)%100);

        return str_pad($num, 2, '0', STR_PAD_LEFT);
    }
}


/**
 * $Log$
 */
?>
